﻿#include <Sys\RenderUnit\SysRenderDatagram\VERTEXRD.HPP>

using namespace CxxlMan;
using namespace Cxxl3D;

/*******************************************/

template <typename CLASS, typename VERTEXFMT>
class CVertexRD:public CLASS
{
  CSmart_Ptr<const tagVertex<VERTEXFMT> > m_Vertex_cPtr;
  bool m_isCrushable;
  mutable bool m_isCallRetrieve;
  wchar_t *m_VertexID;
  C3D_USINT m_VertexNum, m_IndexNum;
  //bool m_haveSetDeposit;
  P2Smart_Ptr<IRetrieveVertex<VERTEXFMT> > m_RetrieveVertex_Ptr;

  // 指示當 Render 單元取出頂點資料後，可以將之清除，內定是不清除的。
  // 須提供一個 IRetrieveVertex，作為須取回頂點資料時的處理方法
  // RetrieveVertex_Arg 不可為 NULL，否則 Crushable() 呼叫無效
  virtual void cxxlFASTCALL Crushable(const Smart_Ptr<IRetrieveVertex<VERTEXFMT> > &RetrieveVertex_Arg)
  {
    if(RetrieveVertex_Arg.isNULL())
      return;

    this->csPreserve.Enter();
    m_isCrushable = true;
    m_RetrieveVertex_Ptr = RetrieveVertex_Arg;
    this->csPreserve.Leave();
  }

  virtual UNICODE_String cxxlFASTCALL  GetVertexID()
  {
    CriticalSecHandle AutoCSH(csPreserve);
    return m_VertexID;
  }

  void cxxlFASTCALL SysInit(const UNICODE_String &VertexID)
  {
    m_VertexID = new wchar_t[VertexID.StrLength()+1];
    wcscpy (m_VertexID, (const wchar_t* )VertexID);
  }

  // 當 Deposit 被清除呼叫之後，會被叫用
  void cxxlFASTCALL haveClearDepositEvent()
  {
//    this->csPreserve.Enter();

//    m_haveSetDeposit = false;

//    this->csPreserve.Leave();
  }

  // 當 SetDeposit() 呼叫之後，會被叫用
  void cxxlFASTCALL haveSetDepositEvent()
  {
    this->csPreserve.Enter();

//    m_haveSetDeposit = true;

    CSmart_Array<const VERTEXFMT> Vertex_Array = NULL;
    CSmart_Array<const C3D_USINT> Index_Array = NULL;

    m_Vertex_cPtr->GetData(m_VertexNum,Vertex_Array,m_IndexNum,Index_Array);

    if(m_isCrushable) 
      m_Vertex_cPtr.Destroy(); // 清除頂點資料

    this->csPreserve.Leave();
  }

  // 通知資料已修改
  void cxxlFASTCALL Modified()
  {
    this->ClearDeposit();
  }

  void cxxlFASTCALL SetVertexData(const CSmart_Ptr<const tagVertex<VERTEXFMT> > &Vertex_Arg)
  {
    this->csPreserve.Enter();
    m_isCallRetrieve = false;
    m_Vertex_cPtr = Vertex_Arg;    
    Modified();
    this->csPreserve.Leave();
  }

  CSmart_Ptr<const tagVertex<VERTEXFMT> > cxxlFASTCALL GetVertexData() const
  {
    csPreserve.Enter();
    CSmart_Ptr<const tagVertex<VERTEXFMT> > Vertex_cPtr = m_Vertex_cPtr;
    csPreserve.Leave();

    if(Vertex_cPtr.isNULL() && m_isCallRetrieve == false)
    {
      m_isCallRetrieve = true;

      csPreserve.Enter();
      Smart_Ptr<IRetrieveVertex<VERTEXFMT> > RetrieveVertex_Ptr = m_RetrieveVertex_Ptr;
      csPreserve.Leave();

      if(RetrieveVertex_Ptr.isNULL() == false)
        RetrieveVertex_Ptr->GetVertex(const_cast<CVertexRD*>(this));
      else
        m_isCallRetrieve = false;
    }

    return Vertex_cPtr;
  }

/*
  // 有取得回覆 true
  virtual bool cxxlFASTCALL GetVertexIndexNum(C3D_USINT &VertexNum, C3D_USINT &IndexNum) const
  {   
    CriticalSecHandle AutoCSH(csPreserve);

    if(m_haveSetDeposit == false)
      return false;

    VertexNum = m_VertexNum;
    IndexNum = m_IndexNum;

    return true;
  }
*/

protected:
  // 儲存容器藉此取得要永續存取的屬性資料
  // 延伸類別須以 virtual 的形式覆寫
  // 並且須呼叫上層類別的此函數
  virtual bool cxxlFASTCALL Ref(Filter *F)
  {
    if(F != NULL && CLASS::Ref(F))
    {
      if(F->Ref(&m_isCrushable, 1, L"isCrushable") == false)
        return false;


      LoadFilter *pLoadFilter = dynamic_cast<LoadFilter*>(F);
      if(pLoadFilter == NULL) // 表示 F 是 SaveFilter
      {        
        F->Ref(m_VertexID, wcslen(m_VertexID) + 1, L"VertexID");
      }
      else // 表示 F 是 LoadFilter
      {
        if( !pLoadFilter->LoadRef( (const wchar_t**)&m_VertexID, L"VertexID") )
          return false;
      }

      if(pLoadFilter->isChk() == false) // 能執行這，表示已正確 Load 了
        this->Modified(); // 對於 m_isCrushable 為 false，load 別的 m_VertexID 的永續資料，也沒法變動已呈現的 3D 樣貌

      return true;
    }
    else
      return false;
  }


/*
  // 儲存容器藉此取得要永續存取的屬性資料
  // 延伸類別須以 virtual 的形式覆寫
  // 並且須呼叫上層類別的此函數
  virtual bool cxxlFASTCALL Ref(Filter *F)
  {
    if(F != NULL && CLASS::Ref(F))
    {
      C3D_USINT VertexNum;
      C3D_USINT IndexNum;

      LoadFilter *pLoadFilter = dynamic_cast<LoadFilter*>(F);
      if(pLoadFilter == NULL) // 表示 F 是 SaveFilter
      {        
        CSmart_Array<const VERTEXFMT> Vertex_Array = NULL;
        CSmart_Array<const C3D_USINT> Index_Array = NULL;

        if(m_Vertex_cPtr.isNULL())
          return false;

        m_Vertex_cPtr->GetData(VertexNum,Vertex_Array,IndexNum,Index_Array);

        F->Ref(&VertexNum, 1, L"VN");
        F->Ref(&IndexNum, 1, L"IN");
        F->Ref( (char *)((const VERTEXFMT *)Vertex_Array), sizeof(VERTEXFMT) * VertexNum, L"V" );
        F->Ref( (const C3D_USINT*)Index_Array, IndexNum, L"I" );
      }
      else // 表示 F 是 LoadFilter
      {
        const VERTEXFMT *pVertex = NULL;
        const C3D_USINT *pIndex = NULL;

        F->Ref(&VertexNum, 1, L"VN");
        F->Ref(&IndexNum, 1, L"IN");

        if( !pLoadFilter->LoadRef( (const char **)&pVertex, L"V") )
          return false;
        if( !pLoadFilter->LoadRef( (const C3D_USINT **)&pIndex, L"I") )
          return false;

        if(pLoadFilter->isChk() == false)
        {
          tagVertex<VERTEXFMT> *ptagVertex = new tagVertex<VERTEXFMT>;
          ptagVertex->SetData(VertexNum, CSmart_Array<const VERTEXFMT>(pVertex), IndexNum, CSmart_Array<const C3D_USINT>(pIndex));
          m_Vertex_cPtr = ptagVertex;
          this->ClearDeposit();
        }
      }      
      return true;
    }
    else
      return false;
  }

*/

public:
  // Constructor
  CVertexRD()
    :cxxlObject(Spirit_Easy),
    cxxlPreserve2(L""), // 在建構時指定 ClassID
    m_Vertex_cPtr(new tagVertex<VERTEXFMT> ),
    m_RetrieveVertex_Ptr(NULL,this,L"RetrieveVertex")
  {
    m_isCrushable = false;
    m_VertexID = NULL;
//    m_haveSetDeposit = false;
    m_isCallRetrieve = false;
  }

  // Destructor
  ~CVertexRD()
  {
    delete [] m_VertexID;
  }
};


/*******************************************/


#define CVertex_NC_ClassID L"ED04F49274074519BA6AC79A3D1848C4"

cxxlObject *cxxlFASTCALL New_CVertexRD_NC();
cxxlPreserve2 *cxxlFASTCALL Regenera_CVertexRD_NC(const wchar_t *ClassID);

class CVertexRD_NC:public CVertexRD< IVertexRD_NC, tagVERTEXFMT_NC >
{

public:
  // Constructor
  CVertexRD_NC()
    :cxxlObject(Spirit_Easy),
    cxxlPreserve2(CVertex_NC_ClassID) // 在建構時指定 ClassID
  {
  }

  // Destructor
  ~CVertexRD_NC()
  {
  }

  friend cxxlObject *cxxlFASTCALL New_CVertexRD_NC();
  friend cxxlPreserve2 *cxxlFASTCALL Regenera_CVertexRD_NC(const wchar_t *ClassID);
};


cxxlObject *cxxlFASTCALL New_CVertexRD_NC()
{
  return new CVertexRD_NC();
}

cxxlPreserve2 *cxxlFASTCALL Regenera_CVertexRD_NC(const wchar_t *ClassID)
{
  if(wcscmp(CVertex_NC_ClassID, ClassID) == 0)
    return new CVertexRD_NC();
  else
    return NULL;
}

/***************************************************************/


#define CVertex_C_ClassID L"B81A8303B9164b9dB7525A6E018C1690"

cxxlObject *cxxlFASTCALL New_CVertexRD_C();
cxxlPreserve2 *cxxlFASTCALL Regenera_CVertexRD_C(const wchar_t *ClassID);


class CVertexRD_C:public CVertexRD< IVertexRD_C, tagVERTEXFMT_C >
{

public:
  // Constructor
  CVertexRD_C()
    :cxxlObject(Spirit_Easy),
    cxxlPreserve2(CVertex_C_ClassID) // 在建構時指定 ClassID
  {
  }

  // Destructor
  ~CVertexRD_C()
  {
  }

  friend cxxlObject *cxxlFASTCALL New_CVertexRD_C();
  friend cxxlPreserve2 *cxxlFASTCALL Regenera_CVertexRD_C(const wchar_t *ClassID);
};

cxxlObject *cxxlFASTCALL New_CVertexRD_C()
{
  return new CVertexRD_C();
}

cxxlPreserve2 *cxxlFASTCALL Regenera_CVertexRD_C(const wchar_t *ClassID)
{
  if(wcscmp(CVertex_C_ClassID, ClassID) == 0)
    return new CVertexRD_C();
  else
    return NULL;
}


/***************************************************************/


#define CVertex_N_ClassID L"7005A40E64354ff7A7901D001A41C70B"

cxxlObject *cxxlFASTCALL New_CVertexRD_N();
cxxlPreserve2 *cxxlFASTCALL Regenera_CVertexRD_N(const wchar_t *ClassID);


class CVertexRD_N:public CVertexRD< IVertexRD_N, tagVERTEXFMT_N >
{

public:
  // Constructor
  CVertexRD_N()
    :cxxlObject(Spirit_Easy),
    cxxlPreserve2(CVertex_N_ClassID) // 在建構時指定 ClassID
  {
  }

  // Destructor
  ~CVertexRD_N()
  {
  }

  friend cxxlObject *cxxlFASTCALL New_CVertexRD_N();
  friend cxxlPreserve2 *cxxlFASTCALL Regenera_CVertexRD_N(const wchar_t *ClassID);
};

cxxlObject *cxxlFASTCALL New_CVertexRD_N()
{
  return new CVertexRD_N();
}

cxxlPreserve2 *cxxlFASTCALL Regenera_CVertexRD_N(const wchar_t *ClassID)
{
  if(wcscmp(CVertex_N_ClassID, ClassID) == 0)
    return new CVertexRD_N();
  else
    return NULL;
}


/***************************************************************/


#define CVertex_NT_ClassID L"8BC7F31539CA4484BAEF1B7F2E2F5B18"

cxxlObject *cxxlFASTCALL New_CVertexRD_NT();
cxxlPreserve2 *cxxlFASTCALL Regenera_CVertexRD_NT(const wchar_t *ClassID);


class CVertexRD_NT:public CVertexRD< IVertexRD_NT, tagVERTEXFMT_NT >
{

public:
  // Constructor
  CVertexRD_NT()
    :cxxlObject(Spirit_Easy),
    cxxlPreserve2(CVertex_NT_ClassID) // 在建構時指定 ClassID
  {
  }

  // Destructor
  ~CVertexRD_NT()
  {
  }

  friend cxxlObject *cxxlFASTCALL New_CVertexRD_NT();
  friend cxxlPreserve2 *cxxlFASTCALL Regenera_CVertexRD_NT(const wchar_t *ClassID);
};

cxxlObject *cxxlFASTCALL New_CVertexRD_NT()
{
  return new CVertexRD_NT();
}

cxxlPreserve2 *cxxlFASTCALL Regenera_CVertexRD_NT(const wchar_t *ClassID)
{
  if(wcscmp(CVertex_NT_ClassID, ClassID) == 0)
    return new CVertexRD_NT();
  else
    return NULL;
}

/***************************************************************/


#define CVertex_T_ClassID L"79FE6BF610A7490eA2DDEC4C4E1148EC"

cxxlObject *cxxlFASTCALL New_CVertexRD_T();
cxxlPreserve2 *cxxlFASTCALL Regenera_CVertexRD_T(const wchar_t *ClassID);


class CVertexRD_T:public CVertexRD< IVertexRD_T, tagVERTEXFMT_T >
{

public:
  // Constructor
  CVertexRD_T()
    :cxxlObject(Spirit_Easy),
    cxxlPreserve2(CVertex_T_ClassID) // 在建構時指定 ClassID
  {
  }

  // Destructor
  ~CVertexRD_T()
  {
  }

  friend cxxlObject *cxxlFASTCALL New_CVertexRD_T();
  friend cxxlPreserve2 *cxxlFASTCALL Regenera_CVertexRD_T(const wchar_t *ClassID);
};

cxxlObject *cxxlFASTCALL New_CVertexRD_T()
{
  return new CVertexRD_T();
}

cxxlPreserve2 *cxxlFASTCALL Regenera_CVertexRD_T(const wchar_t *ClassID)
{
  if(wcscmp(CVertex_T_ClassID, ClassID) == 0)
    return new CVertexRD_T();
  else
    return NULL;
}


